package models

import (
	"fmt";
)

const (
	SNAKE	byte	= 'S';
	LADDER	byte	= 'L';
	NOTHING	byte	= 'O';
)

type PrintMode int

const (
	_		PrintMode	= iota;
	PRINT_PT;			// for point print
	PRINT_NT;			// for node type print
	PRINT_BO;			// for both NT(PT)
)

const RAND_FACT = 8	// lower for more LADDER / SNAKE nodes

type Board struct {
	// array that contains the nodes of the Board
	nodes	[MAX_HEIGHT][MAX_WIDTH]byte;

	// some nodes may have ladder or snake that "jumps" 
	// the players to another node 
	jumpto	[MAX_HEIGHT][MAX_WIDTH]Point;

	num_snakes	int;
	num_ladders	int;
}

func NewBoard() (board *Board) {
	board = new(Board);
	possible_tile := []byte{NOTHING, SNAKE, LADDER};

	board.num_snakes = 0;
	board.num_ladders = 0;

	for i := 0; i < MAX_WIDTH; i++ {
		for j := 0; j < MAX_HEIGHT; j++ {
			to_put := NOTHING;

			// chance of 1/RAND_FACT a node is either 'S'nake or 'L'adder AND
			if (i != 0 || j != 0) && random.Int()%RAND_FACT == 0 {
				to_put = possible_tile[random.Int()%3];

				// if LADDER and at the highest row or SNAKE at the bottom; put nothing
				if (to_put == LADDER && j == MAX_HEIGHT-1) || (to_put == SNAKE && i == 0) {
					to_put = NOTHING
				}

				if to_put == SNAKE {
					// add one as i or j maybe zero and we'll get division by 0
					x := random.Int() % (i + 1);
					y := random.Int() % (j + 1);

					// make sure snake actually penalizes player
					if i == 0 && y == j {
						y--
					} else if j == 0 && x == i {
						x--
					}

					board.jumpto[i][j].X = x;
					board.jumpto[i][j].Y = y;
					board.num_snakes++;

					// make sure that ladder actually rewards player
				} else if to_put == LADDER {
					x := random.Int() % MAX_WIDTH;
					y := random.Int() % (MAX_HEIGHT - 1);

					// case lower height
					if y < j {
						y = j + 1
					} else if y == j {
						// case equal height but lower width
						if x <= i {
							x = i + 1
						}
					}

					board.jumpto[i][j].X = x;
					board.jumpto[i][j].Y = y;
					board.num_ladders++;
				}
			}

			board.nodes[i][j] = to_put;
		}
	}
	return;
}

func (this *Board) PrintBoard(mode PrintMode) {
	var to_print string;
	for j := MAX_HEIGHT - 1; j >= 0; j-- {
		for i := 0; i < 10; i++ {
			switch mode {
			case PRINT_NT:
				to_print = string(this.nodes[i][j])
			case PRINT_BO:
				to_print = string(this.nodes[i][j]);
				to_print += PrintPoint1(i, j);
			case PRINT_PT:
				to_print = PrintPoint1(i, j)
			}

			fmt.Printf("|%s", to_print);
		}
		fmt.Printf("|\n");
	}
}

func (this *Board) PrintJumpto() {
	for i := 0; i < MAX_WIDTH; i++ {
		for j := 0; j < MAX_HEIGHT; j++ {
			if this.nodes[i][j] != NOTHING {
				fmt.Printf("%c - %s: %s\n", this.nodes[i][j], PrintPoint1(i, j), PrintPoint2(this.jumpto[i][j]))
			}
		}
	}
}

func (this *Board) PrintInfo() {
	fmt.Printf("Number of ladders: %d\n", this.num_ladders);
	fmt.Printf("Number of snakes: %d\n", this.num_snakes);
}
